home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 4
/
Amiga Tools 4.iso
/
tools
/
protect-your-privacy
/
p.g.p.
/
pgpsendmail
/
source
/
pgpsendmail.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-02-26
|
17KB
|
485 lines
/*
* $Filename: pgpsendmail.c $
* $Revision: 1.45 $
* $Date: 1994/03/21 14:54:52 $
*
* Copyright (C) 1993 by Peter Simons <simons@peti.GUN.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: pgpsendmail.c,v 1.45 1994/03/21 14:54:52 simons Exp simons $
*
*/
/**************************************************************************
* *
* Section: Macros, Definitions, Includes, Structures *
* *
**************************************************************************/
/************************************* Includes ***********/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <exec/execbase.h>
#include "pgpsendmail.h" /* standard defines */
#include "protos.h" /* protoypes of all available routines */
#include "pgpsendmail_rev.h" /* bumprevision stuff (AmigaOS only) */
/************************************* Prototypes *********/
void my_exit(void);
void sendmail(void);
/************************************* Defines ************/
#define PGP "PGP -fesa <%s >%s %s +batchmode"
#define PGPKEYLIST "UULib:PGPKeys.lst"
#define BODY_ID "Automatically encrypted message-body follows:\n\n"
/************************************* global Variables ***/
static const char __OSVer[] = VERSTAG;
static const char __RCSId[] = "$Id: pgpsendmail.c,v 1.45 1994/03/21 14:54:52 simons Exp simons $";
char PRGNAME[] = "PGPSendmail";
struct NetSupportLibrary *NetSupportBase;
FILE *mailfh, *tmpfh;
char mailfilename[L_tmpnam], tmpfilename[L_tmpnam], encryptedfilename[L_tmpnam], *argline, *tmpbuf;
int exitPipe = 1;
/**************************************************************************
* *
* Section: main program *
* *
**************************************************************************/
int main(int argc, char **argv)
{
extern struct ExecBase *SysBase;
BPTR pipe, tmp_pipe;
char **receipients, *cmdbuf, *header, *tmp, *ptr;
int rc;
/*
* Initialize the requires resources and return if something fails!
*/
if (SysBase->LibNode.lib_Version < 37) {
fprintf(stderr, "%s: Kickstart 2.04 or later is required!", PRGNAME);
return 20;
}
if (atexit(my_exit)) {
fprintf(stderr, "%s: Could not install my exit handler!\n", PRGNAME);
return 20;
}
if (!(NetSupportBase = (struct NetSupportLibrary *) OpenLibrary("netsupport.library", 0L))) {
fprintf(stderr, "%s: Failed opening NetSupport.Library!", PRGNAME);
return 20;
}
if (!(cmdbuf = malloc(MAX_CMDLINELEN)) || (!(tmpbuf = malloc(MY_BUFLEN)))) {
MakeLogEntry(PRGNAME, MLE_FATAL_ERROR, "Failed allocating my buffers!");
return 20;
}
tmpnam(mailfilename);
tmpnam(tmpfilename);
tmpnam(encryptedfilename);
argline = GetOriginalCmdLine(argc, argv); /* Re-build the original commandline, because
* the real sendmail will need it later.
*/
/*
* Copy standard input to a temporary file for security reasons.
*/
if (!(mailfh = fopen(mailfilename, "w"))) {
MakeLogEntry(PRGNAME, MLE_FATAL_ERROR, "Failed opening %s!", mailfilename);
return 20;
}
while (fgets(tmpbuf, MY_BUFLEN, stdin)) {
if (fputs(tmpbuf, mailfh) == EOF) {
MakeLogEntry(PRGNAME, MLE_FATAL_ERROR, "Can't write to %s!", mailfilename);
return 20;
}
}
fclose(mailfh); mailfh = NULL;
MakeLogEntry(PRGNAME, MLE_DEBUG2, "original mail is now in '%s'.", mailfilename);
/*
* Now that the mail is safe, install an exit handler that pipes the
* file to sendmail when we exit, to make sure the mail will not be
* lost under error condition.
*/
if (atexit(sendmail)) {
fprintf(stderr, "%s: Could not install my exit handler!\n", PRGNAME);
return 20;
}
/*
* Load the mail header for RFC routines.
*/
if (!(header = malloc(10*1024))) { /* allocate 10k for the mail header */
MakeLogEntry(PRGNAME, MLE_ERROR, "Failed allocating my buffers!");
return 10;
}
if (!(mailfh = fopen(mailfilename, "r"))) {
MakeLogEntry(PRGNAME, MLE_ERROR, "Failed opening %s!", mailfilename);
return 10;
}
tmp = header;
while (fgets(tmp, MY_BUFLEN, mailfh)) {
if (strlen(tmp) == 1) /* Have we reached the mail body? */
break;
tmp += strlen(tmp);
}
/*
* Determine receipients to decide whom to encrypt to.
*/
receipients = FindReceipients(header);
free(header); /* Header isn't needed anymore. */
if (!receipients || (!*receipients)) {
MakeLogEntry(PRGNAME, MLE_ERROR, "Can't determine receipient of message.");
return 10;
}
else
MakeLogEntry(PRGNAME, MLE_DEBUG2, "receipients (including aliases): %s", ArrayToLine(receipients));
receipients = ExpandAliases(receipients);
if (!receipients || (!*receipients)) {
MakeLogEntry(PRGNAME, MLE_ERROR, "Can't determine receipient of message.");
return 10;
}
else
MakeLogEntry(PRGNAME, MLE_DEBUG2, "receipients (aliases expanded): %s", ArrayToLine(receipients));
MakeDomainAddress(receipients);
/*
* Check wether all keys are available or not.
*/
if ((CheckKeyAvailability(receipients)) == 0) {
MakeLogEntry(PRGNAME, MLE_DEBUG2, "Not all receipients have a valid public key.");
return 0;
}
/*
* Ask user wether this mail should be encrypted or not.
*/
ptr = GetConfig(NULL, CONFIRMENCRYPTION, NULL, "y");
if (ptr[0] == 'y' || ptr[0] == 'Y')
if (!ConfirmEncryption()) {
MakeLogEntry(PRGNAME, MLE_INFO, "Encryption denied by user.");
return 0;
}
/*
* Copy messagebody for encryption.
*/
if (!(tmpfh = fopen(tmpfilename, "w"))) {
MakeLogEntry(PRGNAME, MLE_ERROR, "Failed opening %s!", tmpfilename);
return 5;
}
while (fgets(tmpbuf, MY_BUFLEN, mailfh)) { /* The fileposition is at the begin of the
* mailbody because we read the header earlier.
*/
if (fputs(tmpbuf, tmpfh) == EOF) {
MakeLogEntry(PRGNAME, MLE_ERROR, "Can't write to %s!", tmpfilename);
return 5;
}
}
fclose(mailfh); mailfh = NULL;
fclose(tmpfh); tmpfh = NULL;
/*
* Encrypt message body.
*/
sprintf(tmpbuf, "PGP -ftea <%s >%s %s", tmpfilename, encryptedfilename, ArrayToLine(receipients));
MakeLogEntry(PRGNAME, MLE_DEBUG1, "calling '%s'", tmpbuf);
if (rc = system(tmpbuf)) {
MakeLogEntry(PRGNAME, MLE_ERROR, "PGP returned error code %ld", rc);
return 5;
}
else
MakeLogEntry(PRGNAME, MLE_INFO, "succesfully encrypted the mail for %s", ArrayToLine(receipients));
remove(tmpfilename); /* isn't required anymore */
/*
* Call SendMail to handle the message.
*/
sprintf(tmpbuf, "%s %s", FindConfig(SENDMAIL), argline);
MakeLogEntry(PRGNAME, MLE_DEBUG1, "Calling '%s'", tmpbuf);
/*
* PORT NOTE: Sorry, but I need POpen() again. To make this stuff work on
* another platform, you'll have to re-write it completely.
*/
if (pipe = POpen(tmpbuf, MODE_PIPETO)) {
/* Pipe the mail header to sendmail. */
if (tmp_pipe = Open(mailfilename, MODE_OLDFILE)) {
while (FGets(tmp_pipe, tmpbuf, MY_BUFLEN)) {
FPuts(pipe, tmpbuf);
if (strlen(tmpbuf) == 1) /* header is copied completely */
break;
}
Close(tmp_pipe);
/* Pipe the encrypted mail body to sendmail. */
FPuts(pipe, BODY_ID);
if (tmp_pipe = Open(encryptedfilename, MODE_OLDFILE)) {
while (FGets(tmp_pipe, tmpbuf, MY_BUFLEN))
FPuts(pipe, tmpbuf);
Close(tmp_pipe);
}
exitPipe = 0; /* The mail is sent already, we don't need the sendmail()
* exit handler anymore.
*/
}
rc = PClose(pipe);
}
else {
MakeLogEntry(PRGNAME, MLE_ERROR, "Can't send the encrypted mail!");
return 5;
}
return rc;
}
/**************************************************************************
* *
* SECTION: Subroutines *
* *
**************************************************************************/
/*
* This exit handler will free all resources allocated by the program
* when we exit to make sure nothing is wasted under error condition.
*
* PORT NOTE: Contains system-dependant stuff!
*/
void my_exit(void)
{
/* Close all open files and delete them afterwards. */
if (mailfh)
fclose(mailfh);
if (tmpfh)
fclose(tmpfh);
remove(mailfilename);
remove(tmpfilename);
remove(encryptedfilename);
/* Free all locked files and close the netsupport.library. */
if (NetSupportBase) {
UnLockFiles();
CloseLibrary((struct Library *) NetSupportBase);
}
}
/*
* Pipe the mailfile to sendmail when we exit.
*
* PORT NOTE: Because the AmigaOS doen't know popen(), we have to use
* the routine from the netsupport.library. For other operating systems
* it will be necessary to replace the whole routine!
*/
void sendmail(void)
{
BPTR pipe, fh;
int len;
if (!exitPipe)
return;
sprintf(tmpbuf, "%s %s", FindConfig(SENDMAIL), argline);
MakeLogEntry(PRGNAME, MLE_DEBUG1, "Calling '%s'", tmpbuf);
if (pipe = POpen(tmpbuf, MODE_PIPETO)) {
/* If the file holding the mail is still open, close it first
* to make sure we can access it.
*/
if (mailfh) {
fclose(mailfh); mailfh = NULL;
}
/* Pipe the whole file to sendmail. */
if (fh = Open(mailfilename, MODE_OLDFILE)) {
while (len = Read(fh, tmpbuf, MY_BUFLEN-1)) {
if (len == -1L)
break; /* Read() failed */
if (Write(pipe, tmpbuf, len) == -1L)
break; /* Write() failed */
}
Close(fh);
}
else
MakeLogEntry(PRGNAME, MLE_FATAL_ERROR, "Couldn't open mailfile! Mail is lost!!");
PClose(pipe);
}
else
MakeLogEntry(PRGNAME, MLE_FATAL_ERROR, "Couldn't open pipe to sendmail! Mail is lost!!");
}
char *ArrayToLine(char *array[])
{
char *line;
if (!(line = malloc(MY_BUFLEN)))
return NULL;
line[0] = '\0';
while (*array != NULL) {
strcat(line, *array);
strcat(line, " ");
array++;
}
return line;
}
int CheckKeyAvailability(char *receipients[])
{
FILE *fh;
char *keylist;
int filelength;
if (*receipients == NULL)
return 0; /* No receipient found! */
LockFile(PGPKEYLIST);
if ((fh = fopen(PGPKEYLIST, "r")) == NULL) {
UnLockFile(PGPKEYLIST);
return 0; /* Couldn't open keylist! */
}
fseek(fh, 0L, SEEK_END); filelength = ftell(fh);
/* Determine filelength. */
/* Allocate buffer and read keylist. */
if (keylist = malloc(filelength+1)) {
lseek(fileno(fh), 0, 0);
if ((read(fileno(fh), keylist, filelength)) == -1) {
fclose(fh); /* Couldn't read keylist. */
UnLockFile(PGPKEYLIST);
free(keylist);
return 0;
}
else { /* Read went fine. */
fclose(fh);
UnLockFile(PGPKEYLIST);
keylist[filelength] = '\0';
while (*receipients != NULL) {
if (FindKey(*receipients, keylist) == 0) {
free(keylist);
MakeLogEntry(PRGNAME, MLE_DEBUG1, "No key available for <%s>.", *receipients);
return 0; /* Key is not in keylist. */
}
receipients++;
}
}
}
free(keylist);
return 1; /* Everything is fine. */
}
int FindKey(char *key, char *keylist)
{
char line[MY_BUFLEN];
int i;
while (*keylist != '\0') {
/* Is this a valid key-line? */
if (!strnicmp(keylist, "pub ", strlen("pub "))
|| !strnicmp(keylist, " ", strlen(" ")))
{
for(i = 0; keylist[i] != '\n'; i++)
line[i] = keylist[i];
line[i] = '\0';
if (stristr(line, key))
return 1;
}
/* Find end of line or end of buffer. */
while (*keylist != '\n' && *keylist != '\0')
keylist++;
keylist++;
}
return 0;
}
char *stristr(char *line, char *key)
{
int i, cmplen = strlen(key), end = strlen(line)-cmplen;
for (i = 0; i <= end; i++)
if (strnicmp(&line[i], key, cmplen) == NULL)
return &line[i];
return NULL;
}